#pragma once

#include "types.h"
#include "exceptions.h"

namespace xml {

class const_node {
	friend class implementation;
	friend class const_attribute;
public:
	const_node();
	const_node(const const_node & n);
	const_node & operator = (const const_node & n);
	~const_node();
public:
	string tag() const;		// returns tag
	bool null() const;		// has no data?
	std::stringstream & stream();
	const std::stringstream & stream() const;
protected:
	class const_attribute;
public:
	// attribute access
	template <class T> T attr(const string & name) const;
	template <class T> bool query_attr(const string & name, T & value) const;
	template <class T> T attr(const string & name, def_t<T> d) const;
	void attributes(string_list & list) const;
	const_attribute operator [] (const string & name) const;
	// children access
	void children(const_node_list & nodes, filter f = filter()) const;
	void children(const_node_vector & nodes, filter f = filter()) const;
	const_node child(filter f) const;
	const_node child(filter f, const_node def) const;
protected:
	implementation *			_impl;
	handle						_handle;
	mutable std::stringstream	_stream;
protected:
	const_node(implementation * i, handle h);
	bool get_attr(const string & name, string & value) const;
};

// Most methods of node must have const modificator, even if they modify attributes or childs.
// This is done to allow typing: 
//   void foo(node const & n);
// instead of
//   void foo(node n);
// The first case is preferable since it does not call constructor & destructor of node, 
// and thus do not make false dependency to this xml-library.
// If you really want reference to node, that can not be used to modify the tree,
// choose const_node.

class node : public const_node 
{
	friend class implementation;
	friend class attribute;
public:
	node();
	node(const const_node & n);
protected:
	class attribute;
public:	// attribute access
	/// returns attribute value, throws attribute_not_found
	template <class T> T attr(const string & name) const;
	/// returns attribute value, if not found returns provided default value
	template <class T> T attr(const string & name, def_t<T> d) const;
	/// sets new value for the attribute
	template <class T> void attr(const string & name, const T & value) const;
	/// returns class that allows reading and writing of given attribute
	attribute operator [] (const string & name) const;
public:	// children access
	void children(const_node_list & nodes, filter f = filter()) const;
	void children(node_list & nodes, filter f = filter()) const;
	void children(const_node_vector & nodes, filter f = filter()) const;
	void children(node_vector & nodes, filter f = filter()) const;
public: // single child access
	/// creates a child
	node create(const string & tag) const;	
	/// method throws not_found with default value of last argument 
	node child(filter f, bool create_if_not_found = false) const;
	node child(filter f, node def) const;
public: // clear operations
	/// copies the contents of the node n
	void assign(const const_node & n);
	/// erases all children with given tag and creates one new child
	node replace(const string & tag) const;	
	/// erases all children
	void clear(bool attr = false, bool children = true) const;	
	/// erases itself
	void erase(); ///< ! not const method
protected:
	node(implementation * i, handle h);
	void set_attr(const string & name, const string & value) const;
};

#include "node.inl"

} // xml
